Java 开发使用 mybatis-plus 来执行 sql 操作,往往比 mybatis 能够省时省力,因为 mybatis-plus 封装了很多常用的接口。但对于一些更为复杂的查询来说,mybatis-plus 也相形见绌,还得需要我们自定义 sql 语句。本文就来介绍一下在使用了 mybatis-plus/mybatis 的情况下,如何自定义 sql 语句、动态 sql 等。
一、准备工作
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。在 Java 项目内,配置如下:
1、添加 pom 依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
|
2、修改配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/spring_boot_study?allowMultiQueries=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 username: root password: mycat123 mybatis-plus: # 自定义xml文件路径 mapper-locations: classpath:/mapper/*Mapper.xml # 自定义xml文件中用到的实体类路径 type-aliases-package: com.study.spring.entity configuration: # 开启驼峰映射 map-underscore-to-camel-case: true cache-enabled: false # 返回map时,true:当查询数据为空时字段返回为null;false:不加这个查询数据为空时,字段将被隐藏 call-setters-on-nulls: true # sql日志打印 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
其中 spring.datasource.url 的某些参数说明如下:
- useUnicode:是否使用 Unicode 字符集,如果需要指定编码,则本参数值必须设置为 true 。
- characterEncoding:当 useUnicode 设置为 true 时,指定字符编码。比如可设置为 utf8 。
- serverTimezone:指定 mysql 的时区,默认是 UTC ,与北京时间相差八个小时。平时使用时可设置为 GMT%2B8 或 Asia/Shanghai 。
二、自定义 sql
自定义 sql 分为两种,一种是注解类型,一种是自定义 xml 类型。
1、注解类型
注解类型比较简单,在 mapper 层的接口类方法上使用 @Select、@Update、@Insert、@Delete 等注解并加上自定义的 sql 语句,即可代表 查询、更新、存储、删除 等操作。如下图所示:
虽然使用注解类型也可以实现动态 sql 的写法,但总归是太乱了,没有自定义 xml 类型条理清晰。接下来介绍自定义 xml 类型的写法。
2、自定义 xml 类型
由于配置文件内 mybatis-plus.mapper-locations 定义的 xml 文件路径是:classpath:/mapper/*Mapper.xml 。所以需要先创建 resources/mapper 目录,在这里面创建 xxxMapper.xml ,来自定义 sql 语句。
select
– 映射查询语句
insert
– 映射插入语句
update
– 映射更新语句
delete
– 映射删除语句
1)首先要指定 mapper 接口文件:
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.spring.mapper.NovelMapper"> ... </mapper>
|
这样该 xml 文件就与 NovelMapper.java 这个接口类绑定了。接口类里面的方法名与下文 xml 文件里面的 id 值一一对应。
2)自定义查询 sql
1 2 3 4 5 6
| <select id="findMaxId" resultType="Integer"> select max(id) maxId from novel_type </select>
|
id 为接口类里面的方法名;resultType 指定 sql 返回的结果类型。
3)动态查询 sql
动态查询 sql 通常会使用 \ 和 \ 标签。
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入 “WHERE” 子句。而且,若语句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
使用 \ 标签来判断查询字段是否符合查询条件。\ 标签里面的 test 为判断语句。
xml 里面的变量用 #{} 表示。下面的查询语句的参数类型是 hashmap,参数可直接用 key 值表示。如果接口方法参数里面使用了 @Param(“xxx”),则 xml 里面的参数也要加上 xxx。比如:#{xxx.dl},其中 dl 是 hashmap 的 key 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <select id="getDownloadList" resultType="com.study.spring.entity.NovelEntity" parameterType="hashmap"> select id, download, introduce, novelauthor, novelname, type from novel_type <where> <if test="query.dl != null and query.dl != ''"> download = #{query.dl} </if> <if test="query.nu != null and query.nu != ''"> and novelauthor = #{query.nu} </if> </where> </select>
|
还有一个知识点要说一下:\ ,定义 \ 可以解决类的属性名和数据库列名不一致的问题。
比如我将 NovelEntity 实体类的 novelAuthor 属性修改为 novel_author,这时,返回的 novel_author 字段是接收不到 sql 查询的 novelauthor 值的。但我们可以用 <resultMap>
来解决这种不一致的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
<resultMap type="NovelEntity" id="getDownloadList"> <result property="novel_author" column="novelauthor"/> </resultMap>
<select id="getDownloadList" resultMap="getDownloadList" parameterType="map"> select id, download, introduce, novelauthor, novelname, type from novel_type where download = #{query.dl} </select>
|
4)动态插入 sql
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <insert id="saveNovel" parameterType="com.study.spring.entity.NovelEntity"> insert into novel_type( download <if test="introduce != null and introduce != ''"> ,introduce </if> <if test="novelAuthor !=null and novelAuthor != ''"> ,novelauthor </if> <if test="novelName != null and novelName != ''"> ,novelname </if> <if test="type != null and type != ''"> ,type </if> ) values ( #{download} <if test="introduce != null and introduce != ''"> ,#{introduce} </if> <if test="novelAuthor !=null and novelAuthor != ''"> ,#{novelAuthor} </if> <if test="novelName != null and novelName != ''"> ,#{novelName} </if> <if test="type != null and type != ''"> ,#{type} </if> )
</insert>
|
5)动态更新 sql
假如当只有 novel_author 参数有值,\ 标签会将 \ 标签内的 逗号 隐藏,不会使 sql 语句报错。set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <update id="updateNovelByName" parameterType="com.study.spring.entity.NovelEntity"> update novel_type <set> <if test="download != null and download != ''"> download = #{download}, </if> <if test="introduce != null and introduce != ''"> introduce = #{introduce}, </if> <if test="novel_author !=null and novel_author != ''"> novelauthor = #{novel_author}, </if> <if test="type != null and type != ''"> type = #{type} </if> </set> where novelName = #{novelName} </update>
|
6)动态删除 sql
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <delete id="deleteNoveBy" parameterType="com.study.spring.entity.NovelEntity"> DELETE FROM novel_type <where> <if test="download != null and download != ''"> download = #{download} </if> <if test="introduce != null and introduce != ''"> and introduce = #{introduce} </if> <if test="novel_author !=null and novel_author != ''"> and novelauthor = #{novel_author} </if> <if test="type != null and type != ''"> and type = #{type} </if> <if test="novelName != null and novelName != ''"> and novelName = #{novelName} </if> </where> </delete>
|
三、参考资料
自定义 sql 语句、动态 sql,其实还是用的 mybatis 的那套东西,mybatis-plus 只是将 mybatis 的某些部分又封装了一遍,简便平时的开发。
以上描述的两种自定义 增删改查 SQL 类型在工作中很常用,之所以整理,也是为了系统地了解、测试一遍,希望也能对大家有帮助!